package cn.lili.controller.order;

import cn.lili.common.aop.annotation.PreventDuplicateSubmissions;
import cn.lili.common.context.ThreadContextHolder;
import cn.lili.common.enums.ResultCode;
import cn.lili.common.exception.ServiceException;
import cn.lili.common.security.AuthUser;
import cn.lili.common.security.context.UserContext;
import cn.lili.common.utils.ResultUtil;
import cn.lili.common.utils.StringUtils;
import cn.lili.common.vo.PageVO;
import cn.lili.common.vo.ResponseBean;
import cn.lili.common.vo.ResultMessage;
import cn.lili.common.vo.SearchVO;
import cn.lili.modules.distribution.entity.vos.HomeResult;
import cn.lili.modules.goods.entity.vos.yunxin.BeforeCheckVO;
import cn.lili.modules.goods.entity.vos.yunxin.CallBackVO;
import cn.lili.modules.member.entity.dto.CityDistributionDTO;
import cn.lili.modules.member.entity.dto.MemberAddressDTO;
import cn.lili.modules.member.entity.vo.CityDistributionVO;
import cn.lili.modules.order.kd.service.KdBirdService;
import cn.lili.modules.order.order.entity.dos.Order;
import cn.lili.modules.order.order.entity.dos.OrderCancel;
import cn.lili.modules.order.order.entity.dto.OrderDTO;
import cn.lili.modules.order.order.entity.dto.OrderExportDTO;
import cn.lili.modules.order.order.entity.dto.OrderOverviewDTO;
import cn.lili.modules.order.order.entity.dto.OrderSearchParams;
import cn.lili.modules.order.order.entity.enums.OrderStatusEnum;
import cn.lili.modules.order.order.entity.vo.*;
import cn.lili.modules.order.order.service.OrderCancelService;
import cn.lili.modules.order.order.service.OrderPriceService;
import cn.lili.modules.order.order.service.OrderService;
import cn.lili.modules.order.order.service.TradeService;
import cn.lili.modules.order.payment.TradeCashier;
import cn.lili.modules.payment.entity.dto.PaymentCallback;
import cn.lili.modules.store.client.StoreLogisticsClient;
import cn.lili.modules.store.entity.params.StoreSaleTopParams;
import cn.lili.modules.store.entity.vos.StoreSaleTopVO;
import cn.lili.modules.system.constants.DictConstant;
import cn.lili.mybatis.util.PageUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.apache.shardingsphere.transaction.annotation.ShardingTransactionType;
import org.apache.shardingsphere.transaction.core.TransactionType;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import springfox.documentation.annotations.ApiIgnore;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.List;
import java.util.Objects;

/**
 * 订单API
 *
 * @author Chopper
 * @since 2020/11/17 4:34 下午
 */
@RestController
@RequestMapping("/order")
@Api(tags = "订单API")
@RequiredArgsConstructor
public class OrderController {

    /**
     * 订单
     */
    private final OrderService orderService;

    private final TradeService tradeService;
    /**
     * 订单价格
     */
    private final OrderPriceService orderPriceService;

    private final StoreLogisticsClient storeLogisticsClient;

    private final KdBirdService kdBirdService;

    private final OrderCancelService orderCancelService;


    @ApiOperation(value = "查询订单")
    @GetMapping
    public ResultMessage<Page<OrderSimpleVO>> queryOrder(OrderSearchParams orderSearchParams) {
        return ResultUtil.data(orderService.queryByParams(orderSearchParams));
    }

    @ApiOperation(value = "查询订单导出列表")
    @GetMapping("/queryExportOrder")
    public ResultMessage<List<OrderExportDTO>> queryExportOrder(OrderSearchParams orderSearchParams) {

        //校验导出周期
        orderSearchParams.checkoutExportParams();

        return ResultUtil.data(orderService.queryExportOrder(orderSearchParams));
    }

    @ApiOperation(value = "订单导出列表")
    @GetMapping("/exportExcelByOrder")
    public ResponseEntity<InputStreamResource> exportExcelByOrder(OrderSearchParams orderSearchParams) {

        //校验导出周期
        orderSearchParams.checkoutExportParams();

        return orderService.exportExcelByOrder(orderSearchParams);
    }

    @ApiOperation(value = "查询待发货订单导出列表")
    @GetMapping("/queryExportOrderByWaitShip")
    public ResultMessage<List<OrderExportDTO>> queryExportOrderByWaitShip(OrderSearchParams orderSearchParams) {

        //校验导出周期
        orderSearchParams.checkoutExportParams();

        return ResultUtil.data(orderService.queryExportOrderByWaitShip(orderSearchParams));
    }

    @PreventDuplicateSubmissions
    @ApiOperation(value = "创建电子面单")
    @PostMapping(value = "/{orderSn}/createElectronicsFaceSheet")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "orderSn", value = "订单号", required = true, paramType = "path"),
            @ApiImplicitParam(name = "logisticsId", value = "物流公司", required = true, dataType = "String", paramType = "query")
    })
    public ResultMessage<Object> createElectronicsFaceSheet(@NotNull(message = "参数非法") @PathVariable String orderSn,
                                                            @NotNull(message = "请选择物流公司") String logisticsId) throws Exception {
        return ResultUtil.data(kdBirdService.createElectronicsFaceSheet(orderSn, logisticsId));
    }

    @ApiOperation(value = "下载待发货的订单列表", produces = "application/octet-stream")
    @GetMapping(value = "/downLoadDeliverExcel")
    public void downLoadDeliverExcel() {
        HttpServletResponse response = ThreadContextHolder.getHttpResponse();
        String storeId = Objects.requireNonNull(UserContext.getCurrentUser()).getExtendId();
        //获取店铺已经选择物流公司列表
        List<String> logisticsName = storeLogisticsClient.getStoreSelectedLogisticsName(storeId);
        //下载订单批量发货Excel
        this.orderService.getBatchDeliverList(response, logisticsName);

    }

    @PostMapping(value = "/batchDeliver", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    @ApiOperation(value = "上传文件进行订单批量发货")
    public ResultMessage<Object> batchDeliver(@RequestPart("files") MultipartFile files) {
        orderService.batchDeliver(files);
        return ResultUtil.success();
    }


    @ApiOperation(value = "订单明细")
    @ApiImplicitParam(name = "orderSn", value = "订单编号", required = true, dataType = "String", paramType = "path")
    @GetMapping(value = "/{orderSn}")
    public ResultMessage<OrderDetailVO> detail(@PathVariable String orderSn) {
        return ResultUtil.data(orderService.queryDetail(orderSn));
    }

    @ApiOperation(value = "获取交易trade")
    @ApiImplicitParam(name = "orderSn", value = "订单编号", required = true, dataType = "String", paramType = "path")
    @GetMapping(value = "/getTrade/{orderSn}")
    public ResultMessage<TradeDetailVO> getTrade(@PathVariable String orderSn) {
        return ResultUtil.data(tradeService.getTradeDetail(orderSn));
    }


    @PreventDuplicateSubmissions
    @ApiOperation(value = "修改收货人信息")
    @ApiImplicitParam(name = "orderSn", value = "订单sn", required = true, dataType = "String", paramType = "path")
    @PostMapping(value = "/update/{orderSn}/consignee")
    public ResultMessage<Order> consignee(@NotNull(message = "参数非法") @PathVariable String orderSn, @RequestBody @Valid MemberAddressDTO memberAddressDTO) {
        return ResultUtil.data(orderService.updateConsignee(orderSn, memberAddressDTO));
    }

    @PreventDuplicateSubmissions
    @ApiOperation(value = "修改订单价格")
    @ApiImplicitParams({@ApiImplicitParam(name = "orderSn", value = "订单sn", required = true, dataType = "String", paramType = "path"),
            @ApiImplicitParam(name = "price", value = "订单价格", required = true, dataType = "Double", paramType = "query"),})
    @PutMapping(value = "/update/{orderSn}/price")
    public ResultMessage<Order> updateOrderPrice(@PathVariable String orderSn, @NotNull(message = "订单价格不能为空") @RequestParam Double orderPrice) {
        return ResultUtil.data(orderPriceService.updatePrice(orderSn, orderPrice));
    }

    @PreventDuplicateSubmissions
    @ApiOperation(value = "订单发货")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "orderSn", value = "订单sn", required = true, dataType = "String", paramType = "path"),
            @ApiImplicitParam(name = "logisticsNo", value = "发货单号", required = true, dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "logisticsId", value = "物流公司", required = true, dataType = "String", paramType = "query")
    })
    @PostMapping(value = "/{orderSn}/delivery")
    public ResultMessage<Object> delivery(@NotNull(message = "参数非法") @PathVariable String orderSn,
                                          @NotNull(message = "发货单号不能为空") String logisticsNo,
                                          @NotNull(message = "请选择物流公司") String logisticsId) {
        return ResultUtil.data(orderService.delivery(orderSn, logisticsNo, logisticsId));
    }

    @PreventDuplicateSubmissions
    @ApiOperation(value = "订单览件")
    @PostMapping(value = "/overview")
    public ResultMessage<Object> overview(@RequestBody OrderOverviewDTO orderOverviewDTO) {
        return ResultUtil.data(orderService.overview(orderOverviewDTO.getOrderSns()));
    }

    @ApiOperation(value = "根据核验码获取订单信息")
    @ApiImplicitParam(name = "verificationCode", value = "核验码", required = true, paramType = "path")
    @GetMapping(value = "/getOrderByVerificationCode/{verificationCode}")
    public ResultMessage<Object> getOrderByVerificationCode(@PathVariable String verificationCode) {
        return ResultUtil.data(orderService.getOrderByVerificationCode(verificationCode));
    }

    @PreventDuplicateSubmissions
    @ApiOperation(value = "订单核验")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "orderSn", value = "订单号", required = true, paramType = "path"),
            @ApiImplicitParam(name = "verificationCode", value = "核验码", required = true, paramType = "path")
    })
    @PutMapping(value = "/take/{orderSn}/{verificationCode}")
    public ResultMessage<Object> take(@PathVariable String orderSn, @PathVariable String verificationCode) {
        return ResultUtil.data(orderService.take(orderSn, verificationCode));
    }

    @PreventDuplicateSubmissions
    @ApiOperation(value = "取消订单")
    @ApiImplicitParams({@ApiImplicitParam(name = "orderSn", value = "订单编号", required = true, dataType = "String", paramType = "path"),
            @ApiImplicitParam(name = "reason", value = "取消原因", required = true, dataType = "String", paramType = "query")})
    @PostMapping(value = "/{orderSn}/cancel")
    public ResultMessage<Order> cancel(@ApiIgnore @PathVariable String orderSn, @RequestParam String reason, @RequestParam(required = false) String resultId) {
        return ResultUtil.data(orderService.cancel(orderSn, reason,resultId,null));
    }

    /**
     * 盲盒订单，退货退款
     * 将订单变成可退款状态（已支付）  ==》  退款   ==》 把原来的状态变更回来
     * @param orderSn 订单号
     * @param reason 取消原因
     * @param buyerId 购买人
     */
    @PostMapping("/cancelOrder")
    @Transactional
    @ShardingTransactionType(TransactionType.BASE)
    public ResultMessage<Order> cancelOrder(@RequestParam String orderSn, @RequestParam String reason, @RequestParam String buyerId) {
        Order order = orderService.getBySn(orderSn);
        if (order == null || StringUtils.isEmpty(order.getId())) {
            throw new ServiceException("根据订单号：" + orderSn + "，未获取到订单信息");
        }
        //将订单变成可退款状态（已支付）
        Order cloneOrder = order.clone();
        cloneOrder.setOrderStatus(OrderStatusEnum.PAID.name());
        orderService.updateById(cloneOrder);

        //退款
        LambdaUpdateWrapper<Order> orderLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        orderLambdaUpdateWrapper.eq(Order::getSn, orderSn);
        orderLambdaUpdateWrapper.set(Order::getCancelReason, reason);
        orderLambdaUpdateWrapper.set(Order::getRecycleStatus, DictConstant.RECYCLE_STATUS_02);
        orderService.update(orderLambdaUpdateWrapper);
        orderService.cancel(orderSn, reason, buyerId);

        //把原来的状态变更回来
        Order orderTow = new Order();
        orderTow.setId(order.getId());
        orderTow.setOrderStatus(order.getOrderStatus());
        orderService.updateById(orderTow);

        return ResultUtil.data(order);
    }

    @PreventDuplicateSubmissions
    @ApiOperation(value = "拒绝取消订单")
    @PostMapping(value = "/{orderSn}/cancelResult")
    public ResultMessage<Order> cancelResult(@ApiIgnore @PathVariable String orderSn,@RequestParam String id) {
        return ResultUtil.data(orderService.cancelResult(orderSn,id));
    }

    @PreventDuplicateSubmissions
    @ApiOperation(value = "删除订单")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "orderSn", value = "订单编号", required = true, dataType = "String", paramType = "path")
    })
    @DeleteMapping(value = "/{orderSn}")
    public ResultMessage<Object> deleteOrder(@PathVariable String orderSn) {
        orderService.getBySn(orderSn);
        orderService.deleteOrder(orderSn);
        return ResultUtil.success();
    }

    @PreventDuplicateSubmissions
    @ApiOperation(value = "确认收货")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "orderSn", value = "订单编号", required = true, paramType = "path")
    })
    @PostMapping(value = "/{orderSn}/receiving")
    public ResultMessage<Object> receiving(@NotNull(message = "订单编号不能为空") @PathVariable("orderSn") String orderSn) {
        Order order = orderService.getBySn(orderSn);

        if (order == null) {
            throw new ServiceException(ResultCode.ORDER_NOT_EXIST);
        }
        //判定是否是待收货状态
        if (!order.getOrderStatus().equals(OrderStatusEnum.DELIVERED.name()) && !order.getOrderStatus().equals(OrderStatusEnum.OVERVIEW.name())) {
            throw new ServiceException(ResultCode.ORDER_DELIVERED_ERROR);
        }
        orderService.complete(orderSn);
        return ResultUtil.success();
    }


    @ApiOperation(value = "查询物流踪迹")
    @ApiImplicitParams({@ApiImplicitParam(name = "orderSn", value = "订单编号", required = true, dataType = "String", paramType = "path")})
    @PostMapping(value = "/traces/{orderSn}")
    public ResultMessage<Object> getTraces(@NotBlank(message = "订单编号不能为空") @PathVariable String orderSn) {
        return ResultUtil.data(orderService.getTraces(orderSn));
    }

    @PreventDuplicateSubmissions
    @ApiOperation(value = "开票")
    @ApiImplicitParams({@ApiImplicitParam(name = "orderSn", value = "订单编号", required = true, dataType = "String", paramType = "path")})
    @PostMapping(value = "/receipt/{orderSn}")
    public ResultMessage<Object> invoice(@NotBlank(message = "订单编号不能为空") @PathVariable String orderSn) {
        return ResultUtil.data(orderService.invoice(orderSn));
    }

    /**
     * 壹邦玖回调地址
     */
    @RequestMapping("/callback")
    public ResponseBean callback(@RequestBody CallBackVO callBackVO) {
        return orderService.callback(callBackVO);
    }

    /**
     * 获取供应链的运费
     * @param beforeCheckVO 配送地址 +  sku + 购买数量
     * @return 运费
     */
    @PostMapping("/getFreight")
    public ResultMessage<Object> getFreight(@RequestBody BeforeCheckVO beforeCheckVO) {
        return ResultUtil.data(tradeService.beforeCheck(beforeCheckVO));
    }

    /**
     * 取消订单列表
     */
    @GetMapping(value = "/getOrderCancel")
    @ApiOperation(value = "取消订单列表")
    public ResultMessage<Page<OrderCancel>> getByPage(OrderCancel orderCancel, SearchVO searchVo, PageVO page) {
        AuthUser currentUser = Objects.requireNonNull(UserContext.getCurrentUser());
        orderCancel.setStoreId(currentUser.getExtendId());
        return ResultUtil.data(orderCancelService.page(PageUtil.initPage(page), PageUtil.initWrapper(orderCancel, searchVo)));
    }


    /**
     * 省钱计算器
     *
     * @return 本周申请金额
     */
    @GetMapping("/vip/compute/price")
    public ResultMessage<Object> vipComputePrice() {
        return orderService.vipComputePrice();
    }

    /**
     * 省钱订单
     *
     * @return 订单列表
     */
    @GetMapping("/vip/order/price")
    public ResultMessage<Object> vipOrderPrice(OrderSearchParams orderSearchParams) {
        return orderService.vipOrderPrice(orderSearchParams);
    }

    /**
     * 回收中奖，奖券
     */
    @PutMapping("/recycle")
    public ResultMessage<Object> recycle(@RequestParam String id, String remark) {
        return orderService.recycle(id, remark);
    }


    @GetMapping("/saleRankByOrder")
    @ApiOperation(value = "店铺销量排名")
    public ResultMessage<Page<StoreSaleTopVO>> saleRankByOrder(StoreSaleTopParams params) {
        return ResultUtil.data(orderService.saleRankByOrder(params));
    }

    /**
     * 获取当前下级，所有的区域的订单，将订单地址分成组
     *
     * @return 区域分组
     */
    @GetMapping("/regionalGrouping")
    public ResultMessage<Object> regionalGrouping() {
        return ResultUtil.data(orderService.regionalGrouping());
    }


    @GetMapping("/getCityDistributionComissList")
    @ApiOperation(value ="城主收益列表详情")
    public ResultMessage<CityDistributionVO> getCityDistributionComissList(CityDistributionDTO dto) {
        return ResultUtil.data(orderService.getCityDistributionComissList(dto));
    }


    /**
     * 推送订单
     * @return
     */
    @ApiOperation(value = "推送订单给第三方平台")
    @GetMapping(value = "/pushOrderToThirdGrabOrder")
    public ResultMessage<Object> pushOrderToThirdGrabOrder(@RequestParam("orderNos") String orderNos) {
        return orderService.pushOrderToThirdGrabOrder(orderNos);
    }

    /**
     * 手动处理支付未成功订单补偿
     */
    @ApiOperation(value = "手动处理支付未成功订单补偿")
    @PostMapping(value = "/handlePayNotSuccessOrder")
    public ResultMessage<Object> handlePayNotSuccessOrder(@RequestBody Order order) {
        return orderService.handlePayNotSuccessOrder(order);
    }

    @Resource
    TradeCashier tradeCashier;
    @ApiOperation("测试回调")
    @PostMapping(value = "/testPayCallback")
    public void testPayCallback(@RequestBody PaymentCallback paymentCallback) {
        tradeCashier.paymentCallback(paymentCallback);
    }

    /**
     * 首页订单数量统计
     */
    @GetMapping("/quantity/statistics")
    public ResultMessage<HomeResult> orderQuantityStatistics() {
        return orderService.orderQuantityStatistics();
    }


    /**
     * 订单列表: 收货地址为运营中心本省的分销订单列表
     */
    @GetMapping("/getOperationCenterOrderList")
    @ApiOperation("收货地址为运营中心本省的分销订单列表")
    public ResultMessage<Page<OrderViewVO>> getOperationCenterOrderList(OrderViewVO vo) {
        return ResultUtil.data(orderService.getOperationCenterOrderList(vo));
    }

    /**
     *  订单数量统计
     */
    @GetMapping("/operationCenterOrderStatistics")
    @ApiOperation("订单数量统计")
    public ResultMessage<HomeResult> operationCenterOrderStatistics() {
        return orderService.operationCenterOrderStatistics();
    }

    /**
     * 数据统计  ==> 订单统计/订单金额/订单成本
     */
    @GetMapping("/dataStatistics")
    public ResultMessage<Object> dataStatistics(@RequestHeader("Scene") String scene, String startDate, String endDate) {
        return ResultUtil.data(orderService.dataStatistics(scene, startDate, endDate, false));
    }

    /**
     * 数据统计
     * @param type 1日， 2周， 3月， 4季度
     */
    @GetMapping("/dataAnalysis")
    public ResultMessage<Object> dataStatisticsTable(@RequestHeader("Scene") String scene, Integer type) {
        return orderService.dataAnalysis(scene, type);
    }

    @GetMapping("/getPackGiftOrderList")
    @ApiOperation(value = "礼包商品订单列表")
    public ResultMessage<Page<OrderVO>> getPackGiftOrderList(OrderDTO dto) {
        return ResultUtil.data(orderService.getPackGiftOrderList(dto));
    }

    @GetMapping("/exportPackGiftOrderList")
    @ApiOperation(value = "导出礼包商品订单列表")
    public ResultMessage<Page<OrderVO>> exportPackGiftOrderList(OrderDTO dto) {
        dto.setPageSize(Integer.MAX_VALUE);
        return ResultUtil.data(orderService.getPackGiftOrderList(dto));
    }

    @GetMapping("/getOrderPackInfoByOrderSn")
    @ApiOperation("根据订单号获取礼包订单的类型")
    public ResultMessage<List<OrderPackVO>> getOrderPackInfoByOrderSn(@RequestParam("orderSn") String orderSn) {
        return ResultUtil.data(orderService.getOrderPackInfoByOrderSn(orderSn));
    }
}